﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Net;
using System.Net.Sockets;
using System.Xml;
using System.Threading;
using CTIClassLibrary;
using System.IO;

namespace CTIPay
{
    public partial class FrmMain : Form
    {
        FrmCITIC frmCITIC;
        FrmChinaPnr frmChinaPnr;
        UdpClient CiticUdpListening;

        public FrmMain()
        {
            InitializeComponent();
        }

        private void FrmMain_Load(object sender, EventArgs e)
        {
            try
            {
                SetMessage("初始化……");
                XMLConfig.XMLSettings xmlConfig = XMLConfig.Operation.GetSettings();

                Thread th = new Thread(new ThreadStart(Inite));
                th.Start();

                Common.SettlementTime = xmlConfig.SettlementTime;
                //中信支付监听 UDP 端口
                CiticUdpListening = new UdpClient(xmlConfig.UDP_CITIC);
                AsyncCallback callback = new AsyncCallback(receiveCallback);
                CiticUdpListening.BeginReceive(callback, CiticUdpListening);
            }
            catch (Exception ee)
            {
                SetMessage(ee.Message);
            }
        }

        /// <summary>
        /// 一些耗时的初始化操作
        /// </summary>
        private void Inite()
        {
            try
            {
                BANK_CITIC citic = new BANK_CITIC();
                citic.InitializeSecurity();

                SetMessageDelegate sd = SetMessage;
                BeginInvoke(sd, "中信批次号初始化完毕。" + Common.BatchNo_CITIC_Pay);
            }
            catch (Exception ee)
            {
                BeginInvoke(new SetMessageDelegate(SetMessage), ee.Message);
            }
        }

        /// <summary>
        /// 支付
        /// </summary>
        /// <param name="msg">卡号;有效期;cvv2;金额;订单号</param>
        void Pay(string cardNo, string expired, string cvv2, decimal amount, int orderNo, string phone)
        {
            if (expired.Length == 4)
                expired = expired.Substring(2, 2) + expired.Substring(0, 2);//信用卡有效期:ddyy

            BANK_CITIC citic = new BANK_CITIC();
            DateTime dt = DateTime.Now;
            citic.PaymentEntity.PAN = cardNo;
            citic.PaymentEntity.orderNo = orderNo;
            citic.PaymentEntity.transAmount = Common.CITICAmountFormat(amount);
            citic.PaymentEntity.posTime = dt.ToString("yyyyMMddHHmmss");
            citic.PaymentEntity.posID = Common.TraceNo_CITIC;
            citic.PaymentEntity.expiredDate = expired;
            citic.PaymentEntity.batchNo = Common.BatchNo_CITIC_Pay;
            citic.PaymentEntity.cvv2 = cvv2;
            citic.PaymentEntity.Phone = phone;
            //citic.PaymentEntity.IDNo = "2008010411";
            citic.Pay();

            BeginInvoke(new SetMessageDelegate(SetMessage), citic.XMLSent);
            string info = " 订单号：{0} 支付金额：{1}";
            info = string.Format(info, citic.PaymentEntity.orderNo, citic.PaymentEntity.transAmount);

            if (string.IsNullOrEmpty(citic.ErrorMsg))
            {
                BeginInvoke(new SetMessageDelegate(SetMessage), "中信支付成功！" + info);
            }
            else
            {
                Invoke(new SetMessageDelegate(SetMessage), citic.XMLReceived);
                Invoke(new SetMessageDelegate(SetMessage), citic.ErrorMsg);
            }

            Invoke(new ProgressBarStopDelegate(ProgressBarStop), toolStripProgressBar1);
        }

        /// <summary>
        /// 撤消
        /// </summary>
        /// <param name="orderID"></param>
        /// <returns>1 成功 其他信息 失败</returns>
        string Reversal(string orderID)
        {
            BANK_CITIC citic = new BANK_CITIC();
            citic.PaymentReversal(orderID);
            BeginInvoke(new SetMessageDelegate(SetMessage), citic.XMLSent);
            string info = " 订单号：{0}";
            info = citic.ErrorMsg + string.Format(info, orderID);

            if (string.IsNullOrEmpty(citic.ErrorMsg))
            {
                BeginInvoke(new SetMessageDelegate(SetMessage), "中信撤销成功！" + info);
                return "1";
            }
            else
            {
                Invoke(new SetMessageDelegate(SetMessage), citic.XMLReceived);
                Invoke(new SetMessageDelegate(SetMessage), info);
            }

            return info;
        }

        /// <summary>
        /// 退款
        /// </summary>
        /// <param name="orderID"></param>
        /// <param name="amount"></param>
        /// <returns>1 成功 其他信息 失败</returns>
        string Reund(string orderID,decimal amount)
        {
            BANK_CITIC citic = new BANK_CITIC();
            citic.PaymentRefund(orderID, amount);
            BeginInvoke(new SetMessageDelegate(SetMessage), citic.XMLSent);
            string info = " 订单号：{0} 退款金额：{1}";
            info = citic.ErrorMsg + string.Format(info, orderID, amount);

            if (string.IsNullOrEmpty(citic.ErrorMsg))
            {
                BeginInvoke(new SetMessageDelegate(SetMessage), "中信退款成功！" + info);
                return "1";
            }
            else
            {
                Invoke(new SetMessageDelegate(SetMessage), citic.XMLReceived);
                Invoke(new SetMessageDelegate(SetMessage), info);
            }

            return info;
        }

        delegate void SetMessageDelegate(string msg);
        delegate void EnableToolStripMenuItemDelegate(ToolStripMenuItem menu);
        delegate void EnableButtonDelegate(Button b);
        delegate void ProgressBarStopDelegate(ToolStripProgressBar bar);

        void EnableToolStripMenuItem(ToolStripMenuItem menu)
        {
            menu.Enabled = !menu.Enabled;
        }

        void EnableButton(Button b)
        {
            b.Enabled = !b.Enabled;
        }

        void ProgressBarStop(ToolStripProgressBar bar)
        {
            bar.Style = ProgressBarStyle.Blocks;
        }

        void SetMessage(string msg)
        {
            this.richTextBox1.Text += ">>> " + DateTime.Now.ToString() + System.Environment.NewLine;
            this.richTextBox1.Text += "    " + msg + System.Environment.NewLine + System.Environment.NewLine;

            richTextBox1.SelectionStart = richTextBox1.Text.Length;
            richTextBox1.ScrollToCaret();

            if (richTextBox1.Lines.Length > 999)
                this.richTextBox1.Text = string.Empty;
        }

        private void receiveCallback(IAsyncResult ar)
        {
            UdpClient u = (UdpClient)(ar.AsyncState);

            if (u == null || u.Client == null)// u == null 判断失败,u 似乎不会为空
                return;//这里线程结束(由 CtiUdpListening.Close() 触发),返回
            else
            {
                //Thread.CurrentThread.Join(3000);// 3 秒内不会接收新的消息
                //重新启动接收线程
                AsyncCallback callback = new AsyncCallback(receiveCallback);
                u.BeginReceive(callback, u);
            }

            IPEndPoint ep = new IPEndPoint(IPAddress.Any, 0);
            Byte[] receiveBytes = u.EndReceive(ar, ref ep);
            string receiveString = Encoding.Default.GetString(receiveBytes);
            string receiveData = string.Empty;
            string msg = string.Format("收到UDP包({0})：{1}", ep.Address, receiveString);
            BeginInvoke(new SetMessageDelegate(SetMessage), msg);
            msg = System.Web.HttpUtility.HtmlEncode(msg);//进行html编码，否则浏览器无法正常显示xml格式的包

            try
            {
                XmlDocument xd = new XmlDocument();
                xd.LoadXml(receiveString);
                XmlNode xn = xd.ChildNodes[0];
                string msgType = xn.Name.ToLower();

                if (msgType == "sasendmsg")//<SaSendMsg id='406' seq='1' msgseq='13865933944' msgtype='11' data='卡号;有效期;cvv2;金额;订单号' addr='192.168.1.230:8082' /> 
                {
                    string phone = xn.Attributes["msgseq"].Value;

                    //如果是坐席主动回拨给支付失败的用户，phone就会为空，需要后面用webservice由订单号来取
                    //if (string.IsNullOrEmpty(phone))
                    //{
                    //    string err = "主叫号码为空？无法支付！";
                    //    throw new Exception(err);
                    //}

                    receiveData = xn.Attributes["data"].Value;

                    if (!string.IsNullOrEmpty(receiveData))
                    {
                        BeginInvoke(new SetMessageDelegate(SetMessage), "开始中信支付……");
                        string[] array = receiveData.ToString().Split(';');
                        string cardNo = array[0];
                        string expired = array[1];
                        string cvv2 = array[2];
                        decimal amount = decimal.Parse(array[3]);
                        int orderNo = int.Parse(array[4]);

                        Pay(cardNo, expired, cvv2, amount, orderNo, phone);
                    }
                    else
                    {
                        string err = string.Format("未收集到用户按键内容，无法支付！ 电话：{0}", phone);
                        throw new Exception(err);
                    }
                }
                else if (msgType == "reversal")//<Reversal OrderID='406' /> 
                {
                    receiveData = xn.Attributes["OrderID"].Value;
                    string ret = Reversal(receiveData);

                    string xml = "<Reversal OrderID='{0}' Flag='{1}' />";
                    xml = string.Format(xml, receiveData, ret);

                    Byte[] xmlByte = Encoding.Default.GetBytes(xml);
                    u.Send(xmlByte, xmlByte.Length, ep);
                }
                else if (msgType == "refund")//<Refund OrderID='406' Amount='1380' /> 
                {
                    receiveData = xn.Attributes["OrderID"].Value;
                    string ret = Reund(receiveData, decimal.Parse(xn.Attributes["Amount"].Value));

                    string xml = "<Refund OrderID='{0}' Flag='{1}' />";
                    xml = string.Format(xml, receiveData, ret);

                    Byte[] xmlByte = Encoding.Default.GetBytes(xml);
                    u.Send(xmlByte, xmlByte.Length, ep);
                }
            }
            catch (Exception ee)
            {
                BeginInvoke(new SetMessageDelegate(SetMessage), ee.Message);
                Common.LogIt(msg, "支付");
                Common.LogIt(ee.Message, "支付");
            }
        }

        private void 登录ToolStripMenuItem_Click(object sender, EventArgs e)
        {
            try
            {
                登录ToolStripMenuItem.Enabled = false;
                SetMessage("正在登录中信支付网关……");
                toolStripProgressBar1.Style = ProgressBarStyle.Marquee;

                Thread th = new Thread(new ThreadStart(Login));
                th.Start();
            }
            catch (Exception ee)
            {
                SetMessage(ee.Message);
            }
        }

        void Login()
        {
            BANK_CITIC citic = new BANK_CITIC();
            citic.Login();
            Invoke(new SetMessageDelegate(SetMessage), citic.XMLSent);

            if (string.IsNullOrEmpty(citic.ErrorMsg))
            {
                Invoke(new SetMessageDelegate(SetMessage), "中信支付网关登录成功!");

                Invoke(new EnableToolStripMenuItemDelegate(EnableToolStripMenuItem), 登出ToolStripMenuItem);
                Invoke(new EnableToolStripMenuItemDelegate(EnableToolStripMenuItem), 结算ToolStripMenuItem);
                Invoke(new EnableToolStripMenuItemDelegate(EnableToolStripMenuItem), 支付测试ToolStripMenuItem);
                Invoke(new EnableButtonDelegate(EnableButton), btnCitic);
            }
            else
            {
                Invoke(new SetMessageDelegate(SetMessage), citic.XMLReceived);
                Invoke(new SetMessageDelegate(SetMessage), citic.ErrorMsg);
                Invoke(new EnableToolStripMenuItemDelegate(EnableToolStripMenuItem), 登录ToolStripMenuItem);
            }

            Invoke(new ProgressBarStopDelegate(ProgressBarStop), toolStripProgressBar1);
        }

        void Logout()
        {
            BANK_CITIC citic = new BANK_CITIC();
            citic.Logout();
            Invoke(new SetMessageDelegate(SetMessage), citic.XMLSent);

            if (string.IsNullOrEmpty(citic.ErrorMsg))
            {
                Invoke(new SetMessageDelegate(SetMessage), "中信支付网关登出成功!");

                Invoke(new EnableToolStripMenuItemDelegate(EnableToolStripMenuItem), 登录ToolStripMenuItem);
                Invoke(new EnableToolStripMenuItemDelegate(EnableToolStripMenuItem), 结算ToolStripMenuItem);
                Invoke(new EnableToolStripMenuItemDelegate(EnableToolStripMenuItem), 支付测试ToolStripMenuItem);
                Invoke(new EnableButtonDelegate(EnableButton), btnCitic);
            }
            else
            {
                Invoke(new SetMessageDelegate(SetMessage), citic.XMLReceived);
                Invoke(new SetMessageDelegate(SetMessage), citic.ErrorMsg);
                Invoke(new EnableToolStripMenuItemDelegate(EnableToolStripMenuItem), 登出ToolStripMenuItem);
            }

            Invoke(new ProgressBarStopDelegate(ProgressBarStop), toolStripProgressBar1);
        }

        private void 登出ToolStripMenuItem_Click(object sender, EventArgs e)
        {
            登出ToolStripMenuItem.Enabled = false;
            toolStripProgressBar1.Style = ProgressBarStyle.Marquee;
            Thread th = new Thread(new ThreadStart(Logout));
            th.Start();
        }

        private void 管理ToolStripMenuItem_Click(object sender, EventArgs e)
        {
            frmCITIC = new FrmCITIC();
            frmCITIC.ShowDialog();
        }

        private void 管理ToolStripMenuItem1_Click(object sender, EventArgs e)
        {
            frmChinaPnr = new FrmChinaPnr();
            frmChinaPnr.ShowDialog();
        }

        private void 结算ToolStripMenuItem_Click(object sender, EventArgs e)
        {
            Thread th = new Thread(new ThreadStart(Settlement));
            th.Start();
        }

        private void Settlement()
        {
            Invoke(new SetMessageDelegate(SetMessage), "结算!!!!");
            BANK_CITIC citic = new BANK_CITIC();
            citic.Settlement(Common.BatchNo_CITIC_Pay);
            Invoke(new SetMessageDelegate(SetMessage), citic.XMLSent);

            if (string.IsNullOrEmpty(citic.ErrorMsg))
            {
                Invoke(new SetMessageDelegate(SetMessage), "中信支付网关结算成功!");
                Invoke(new SetMessageDelegate(SetMessage), citic.XMLReceived);
                Common.hasSettled = false;
            }
            else
            {
                Invoke(new SetMessageDelegate(SetMessage), citic.XMLReceived);
                Invoke(new SetMessageDelegate(SetMessage), citic.ErrorMsg);
            }
        }

        private void 支付测试ToolStripMenuItem_Click(object sender, EventArgs e)
        {
            //toolStripProgressBar1.Style = ProgressBarStyle.Marquee;
            //Thread th = new Thread(new ParameterizedThreadStart(Pay));
            //th.Start("23;1234;456;0.1;" + DateTime.Now.ToString("hhmmss"));
            //Pay("'23;1234;456;1200.01;25009");

            //<SaSendMsg id='406' seq='1' msgseq='139555' msgtype='11' data='4033910000413867;1705;437;1380;2792777' addr='192.168.1.230:8082' />
        }

        private void timerKeepAlive_Tick(object sender, EventArgs e)
        {
            DateTime dtNow = DateTime.Now;
            this.lblTime.Text = dtNow.ToString();
            BANK_CITIC citic = new BANK_CITIC();
            citic.MaintainSession();

            SetMessage("MaintainSession..." + dtNow.Hour + " " + Common.hasSettled.ToString());

            if (!Common.hasSettled && dtNow.Hour == Common.SettlementTime)//晚上10点开始自动结算（最多尝试12次），银行在12点左右开始跑批次
            {
                Thread th = new Thread(new ThreadStart(Settlement));
                th.Start();
            }

            if (dtNow.Hour == Common.SettlementTime + 1)//新的结算周期开始
                Common.hasSettled = false;
        }

        private void 退出ToolStripMenuItem_Click(object sender, EventArgs e)
        {
            Application.ExitThread();//若没有该语句，将需要点击2次“退出”菜单，才能关闭程序
            Application.Exit();
        }

        private void FrmMain_FormClosing(object sender, FormClosingEventArgs e)
        {
            this.WindowState = FormWindowState.Minimized;
            this.ShowInTaskbar = false;
            e.Cancel = true;
        }

        private void notifyIcon1_DoubleClick(object sender, EventArgs e)
        {
            this.WindowState = FormWindowState.Normal;
            this.ShowInTaskbar = true;
        }

        private void btnPay_Click(object sender, EventArgs e)
        {
            //toolStripProgressBar1.Style = ProgressBarStyle.Marquee;
            //Thread th = new Thread(new ParameterizedThreadStart(Pay));
            //th.Start(txtPay.Text.Trim());
        }
    }
}
